{
  Copyright 2012 Sergey Ostanin

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
}

unit QuestionBrowser;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  StdCtrls, VisualUtils, LCLType, Windows, Types, LMessages;

type
  TQuestionBrowserForm = class(TForm)
    btnSelect: TButton;
    lbxQuestions: TListBox;
    pnlBottom: TPanel;
    procedure FormShortCut(var Msg: TLMKey; var Handled: Boolean);
    procedure FormShow(Sender: TObject);
    procedure lbxQuestionsDblClick(Sender: TObject);
    procedure lbxQuestionsDrawItem(Control: TWinControl; Index: Integer;
      ARect: TRect; State: TOwnerDrawState);
  private
    FCurrentQuestion: Integer;
    FQuestionNumberWidth: Integer;
    FSpacing: Integer;
    procedure Prepare(QuestionTitles: TStrings; CurrentQuestion: Integer);
    function GetSelectedQuestion: Integer;
    { private declarations }
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    class function OpenModal(QuestionTitles: TStrings; var SelectedQuestion: Integer): Boolean;
    { public declarations }
  end; 

implementation

{$R *.lfm}

{ TQuestionBrowserForm }

procedure TQuestionBrowserForm.lbxQuestionsDrawItem(Control: TWinControl;
  Index: Integer; ARect: TRect; State: TOwnerDrawState);
var
  c: TCanvas;
  r1, r2: TRect;
  ts: TTextStyle;
begin
  c := lbxQuestions.Canvas;
  c.FillRect(ARect);

  if Index = FCurrentQuestion then
    c.Font.Style := [fsBold]
  else
    c.Font.Style := [];

  if not (odSelected in State) then
  begin
    if lbxQuestions.Items.Objects[Index] = nil then
      c.Font.Color := clWindowText
    else
      c.Font.Color := clGrayText;
  end;

  r1 := ARect;
  r1.Right := r1.Left + FQuestionNumberWidth;
  ts := c.TextStyle;
  ts.Alignment := taRightJustify;
  c.TextRect(r1, r1.Left, r1.Top, IntToStr(Index+1), ts);

  r2 := ARect;
  r2.Left := r1.Right + FSpacing;
  c.TextRect(r2, r2.Left, r2.Top, lbxQuestions.Items[Index]);
end;

procedure TQuestionBrowserForm.lbxQuestionsDblClick(Sender: TObject);
var
  p: TPoint;
begin
  p := lbxQuestions.ScreenToClient(Mouse.CursorPos);
  if lbxQuestions.GetIndexAtXY(p.x, p.y) <> -1 then
    ModalResult := mrOk;
end;

procedure TQuestionBrowserForm.FormShortCut(var Msg: TLMKey;
  var Handled: Boolean);
begin
  if Msg.CharCode = VK_ESCAPE then
  begin
    ModalResult := mrCancel;
    Handled := TRUE;
  end;
end;

procedure TQuestionBrowserForm.FormShow(Sender: TObject);
begin
  FSpacing := lbxQuestions.Canvas.TextWidth('00');
  lbxQuestions.Canvas.Font.Style := [fsBold];
  FQuestionNumberWidth := lbxQuestions.Canvas.TextWidth('00000');
end;

procedure TQuestionBrowserForm.Prepare(QuestionTitles: TStrings;
  CurrentQuestion: Integer);
var
  m: TLCLTextMetric;
begin
  if Canvas.GetTextMetrics(m) then
    lbxQuestions.ItemHeight := m.Height + 2;
  lbxQuestions.Items.Assign(QuestionTitles);
  FCurrentQuestion := CurrentQuestion;
  lbxQuestions.ItemIndex := CurrentQuestion;
end;

function TQuestionBrowserForm.GetSelectedQuestion: Integer;
begin
  if (lbxQuestions.ItemIndex >= 0) and (lbxQuestions.ItemIndex < lbxQuestions.Items.Count) then
    Result := lbxQuestions.ItemIndex
  else
    Result := FCurrentQuestion;
end;

procedure TQuestionBrowserForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_COMPOSITED;
end;

class function TQuestionBrowserForm.OpenModal(QuestionTitles: TStrings;
  var SelectedQuestion: Integer): Boolean;
var
  Form: TQuestionBrowserForm;
begin
  Form := TQuestionBrowserForm.Create(nil);
  try
    Form.Width := ScalePixels(825);
    Form.Height := ScalePixels(550);

    RestoreFormPosition(Form);
    Form.Prepare(QuestionTitles, SelectedQuestion);

    Result := ShowModalForm(Form) = mrOk;
    if Result then
      SelectedQuestion := Form.GetSelectedQuestion;
  finally
    Form.Free;
  end;
end;

end.

